#include "Brodocast.h"

#include <iostream>
#include <boost/asio.hpp>

using namespace std;

Brodocast * Brodocast::m_instacia = 0x0;

Brodocast::Brodocast()
{
    m_grupo = 0x0;
    m_config = 0x0;

    boost::asio::io_service io_service;

    m_comunicadorUDP = new ComunicadorUDP(io_service);
    io_service.run();

}

Brodocast *Brodocast::getBrodocast()
{
    if(m_instacia == 0x0)
    {
        m_instacia = new Brodocast;
    }
    return m_instacia;
}

Brodocast *Brodocast::criaBrodocast(ConfiguracaoBrodocast *config)
{
    Brodocast *novoBrodocast = 0x0;

    novoBrodocast = getBrodocast();
    novoBrodocast->m_grupo = new Grupo(config->nome());
    novoBrodocast->m_config = config;

    return novoBrodocast;
}

Brodocast::~Brodocast()
{
    if(m_grupo != 0x0)
        delete m_grupo;

    m_grupo = 0x0;

    if(m_config != 0x0)
        delete m_config;
    m_config = 0x0;
}

void Brodocast::buscaGrupo(list<Grupo *> &lista)
{
    try
    {
      boost::asio::io_service io_service;

      udp::socket s(io_service);

      s.open(boost::asio::ip::udp::v4());

      s.set_option(boost::asio::ip::udp::socket::reuse_address(true));
      s.set_option(boost::asio::socket_base::broadcast(true));

      using namespace std; // For strlen.

      const unsigned max_length = 100;
      std::cout << "Enter message: ";
      char request[max_length] = "GRUPO";
      size_t request_length = strlen(request);

      boost::asio::ip::udp::endpoint broadcast(boost::asio::ip::address_v4::broadcast(), ComunicadorUDP::m_porta);

      s.send_to(boost::asio::buffer(request, request_length), broadcast);

      char reply[max_length];
      udp::endpoint sender_endpoint;
      size_t reply_length = s.receive_from(
          boost::asio::buffer(reply, max_length), sender_endpoint);

      std::cout << "Resposta de " << sender_endpoint.address().to_string() << " é:" << std::endl;
      std::cout.write(reply, reply_length);
      std::cout << "\n";

    }
    catch (std::exception& e)
    {
      std::cerr << "Exception: " << e.what() << "\n";
    }


    Grupo *grupo = new Grupo("A");
    grupo->novoNodo(new Nodo("NAA"));
    grupo->novoNodo(new Nodo("NAB"));
    grupo->novoNodo(new Nodo("NAC"));
    grupo->novoNodo(new Nodo("NAD"));
    lista.push_back(grupo);

    grupo = new Grupo("B");
    grupo->novoNodo(new Nodo("NBA"));
    grupo->novoNodo(new Nodo("NBB"));
    grupo->novoNodo(new Nodo("NBC"));
    grupo->novoNodo(new Nodo("NBD"));
    lista.push_back(grupo);

    grupo = new Grupo("C");
    grupo->novoNodo(new Nodo("NCA"));
    grupo->novoNodo(new Nodo("NCB"));
    grupo->novoNodo(new Nodo("NCC"));
    grupo->novoNodo(new Nodo("NCD"));
    lista.push_back(grupo);
}

Brodocast *Brodocast::entrar(Grupo *grupo)
{
    Brodocast *novoBrodo = getBrodocast();
    novoBrodo->m_grupo = grupo;

    return novoBrodo;
}

void Brodocast::enviar(const char *msg) // Tirei um warning com este const char
{
    if(m_grupo != 0x0)
    {
        // Aqui a mensagem tem que ser trata, empacotada


        // Aqui a mensagem é enviada para todos nodos do grupo
        Nodo* nodo;
        list<Nodo*>::iterator in;
        for(in = m_grupo->inicioNodos() ; in != m_grupo->fimNodos() ; in++)
        {
            nodo = (*in);

            cout << "Enviando msg \"" << msg << "\" para nodo " << nodo->nome() << endl;
        }
    }
}

string Brodocast::recebe()
{
    return string("");
}
